package callback.impl;

import app.FileMeta;
import callback.FileScannerCallBack;
import util.DBUtil;
import util.PinyinUtil;
import util.Util;

import javax.swing.plaf.nimbus.State;
import java.io.File;
import java.sql.*;
import java.util.ArrayList;
import java.sql.Date;
import java.util.List;

//将文件保存到数据库
public class FileSave2DB implements FileScannerCallBack {
    /**
     * 每次选择数据库，都会检查数据的数据与当前选择的数据是否一致。
     * @param dir
     */
    @Override
    public void callback(File dir) {
        //边界，file不为空，
        File[] files = dir.listFiles();
        if (files != null && files.length != 0){
            //扫描当前路径下的文件
            List<FileMeta> locals = new ArrayList<>();
            //2，查询当前进入的目录下的文件信息
            for (File file: files) {//遍历当前目录下的所有文件
                FileMeta meta = new FileMeta();
                setCommonFiled(meta,file);//创建meta对象，将文件的属性设置为到对象中
                if (file.isDirectory()){//是文件夹
                    meta.setIsDirectory(true);//是文件夹就设置true。文件大小不设置，默认为null，因为是包装类
                }else {
                    meta.setIsDirectory(false);//是文件，就设置为false，
                    meta.setSize(file.length());//文件大小设置为文件的长度，默认是二进制编码
                }
                locals.add(meta);
            }
            //1，从数据库中查找当前路径的子文件;
            List<FileMeta> dbFiles = query(dir);


            //3.2本地没有数据库中删除
            for (FileMeta meta: dbFiles){
                if (!locals.contains(meta)){
                    delete(meta);
                }
            }
            //3.1本地有的，数据库中没有插入
            for(FileMeta meta:locals){
                if (!dbFiles.contains(meta)){//如果本地数据库中不包含
                    save(meta);
                }
            }
        }
    }

    /**
     * 如果本地该数据，数据中没有，将本地中的数据保存到数据库中
     * @param meta
     */
    private void save(FileMeta meta) {
        Connection conn = null;
        PreparedStatement ps = null;
        String sql = "insert into file_meta values(?,?,?,?,?,?,?)";
        try {
            conn = DBUtil.getConnection();
            ps = conn.prepareStatement(sql);
            ps.setString(1,meta.getName());
            ps.setString(2,meta.getPath());
            ps.setBoolean(3,meta.getIsDirectory());
            if (!meta.getIsDirectory()){
                //是文件时才设置大小
                ps.setLong(4,meta.getSize());
            }

            ps.setTimestamp(5,new Timestamp(meta.getLastModified().getTime()));
            //如果文件名是否包含中文
            if(PinyinUtil.containsChinese(meta.getName())){
                String[] pinyins = PinyinUtil.getPinyinByFileName(meta.getName());
                ps.setString(6,pinyins[0]);
                ps.setString(7,pinyins[1]);
            }
//            System.out.println("开始保存文件信息到数据库" + ps);
            int i = ps.executeUpdate();
//            System.out.println("保存了 "+i+" 行信息");
        }catch (SQLException e){
            System.err.println("数据插入失败，请检查sql语句");
            e.printStackTrace();
        }finally {
            DBUtil.close(ps);
        }
    }

    /**
     * 如果本地中没有该文件，但是数据库中有，就将数据库中的数据删除，
     * @param meta
     */
    private void delete(FileMeta meta) {
        Connection conn = null;
        PreparedStatement ps = null;
        /*
        文件名称和路径都相同才可以删除，保证删除的是指定路径下的文件
        如果要删除的是一个文件夹：那么删除本文件夹 name = ? and path = ?
                                删除文件夹下的子文件 path = ? //第一级目录
                                删除子文件夹的多级目录： path like ?;
         */

        try {
            String sql = "delete from file_meta where (name = ? and path = ? )";
            if (meta.getIsDirectory()){
                sql += " or path = ?";//第一级目录
                sql += " or path like ?";//所有子目录
            }
            System.out.println(sql);
            conn = DBUtil.getConnection();
            ps = conn.prepareStatement(sql);
            ps.setString(1,meta.getName());
            ps.setString(2,meta.getPath());
            if (meta.getIsDirectory()){
                //第三个参数 D://A//c.txt -> 要输出A文件夹 要删除c.txt : c.txt的路径为 D:// + A
                ps.setString(3,meta.getPath() + File.separator + meta.getName());
                ps.setString(4,meta.getPath() + File.separator + meta.getName() +
                        File.separator +"%");//这里多加一个\\表示避免删除和当前文件目录模糊相似的文件，比如删除A，比卖你删除AA文件夹
            }
//            System.out.println("开始删除文件信息到数据库" + ps);
            int i = ps.executeUpdate();
//            System.out.println("删除了几行数据"+i);
//            if(meta.getIsDirectory()){
//                System.out.println("删除文件夹成功" + meta.getName() + "共删除" + i + "个文件");
//            }else {
//                System.out.println("删除文件" + meta.getName() + "成功");
//            }
        }catch (SQLException e){
            System.err.println("数据删除失败，请检查sql语句");
            e.printStackTrace();
        }finally {
            DBUtil.close(ps);
        }
    }

    /**
     * 从数据库中查询数据
     * @param file
     * @return
     */
    private List<FileMeta> query(File file) {
        //查询结果集容器
        List<FileMeta> dbFiles = new ArrayList<>();
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet res = null;
        try {
            conn = DBUtil.getConnection();
            /*
            数据库中保存的当前文件的父路径，所以要查询文件的信息，传入的是当前文件的父路径，
            而当前文件的父路径可能存在多个子文件，如果插入的父路径不存在，
             */
            String sql = "select name,path,is_directory,last_modified,size from file_meta"+
                    " where path = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1,file.getPath());
            res = ps.executeQuery();
            while (res.next()){
                FileMeta meta = new FileMeta();
                meta.setName(res.getString("name"));
                meta.setPath(res.getString("path"));
                meta.setIsDirectory(res.getBoolean("is_directory"));
                meta.setLastModified(new Date(res.getTimestamp("last_modified").getTime()));
                if (!meta.getIsDirectory()){
                    meta.setSize(res.getLong("size"));
                }
                dbFiles.add(meta);
            }
        }catch (SQLException e){
            System.err.println("数据库查询失败");
            e.printStackTrace();
        }finally {
            DBUtil.close(ps,res);
        }
        return dbFiles;
    }

    /**
     * 设置元文件的文件名，文件路径和最后修改时间，这些是共性的，可以抽取，减少代码冗余
     * @param meta
     * @param file
     */
    private void setCommonFiled (FileMeta meta, File file){
        meta.setName(file.getName());
        meta.setPath(file.getParent());
        meta.setLastModified(new Date(file.lastModified()));
    }
}
